package com.syezon.wifikey.wifi;

import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
import android.net.wifi.ScanResult;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;

import com.blankj.utilcode.util.PermissionUtils;
import com.syezon.android.base.utils.LogUtils;
import com.syezon.wifikey.home.info.WifiListInfo;
import com.syezon.wifikey.utils.GpsUtil;
import com.syezon.wifikey.utils.LowVersionPermissionUtils;
import com.syezon.wifikey.utils.Utils;
import com.syezon.wifikey.utils.WifiUtil;
import com.syezon.wifikey.wifi.info.WifiInfo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class WifiListUtils {

    private static final String TAG = WifiListUtils.class.getSimpleName();

    public static final int WIFI_LEVEL = 5;

    private static final int MSG_SCAN_WIFI = 1;
    private static final long DURATION = 5L * 1000;
    private static final long UPDATE_LIST_TIME = 5L * 1000;
    private long mLastUpdateTimestamp;

    private long mLastTimestamp;

    private ScanResultReceiver scanResultReceiver;
    private WifiStateChangeReceiver wifiStateChangeReceiver;
    private GPSStateReceiver gpsStateReceiver;
    private WifiManager wifiManager;

    private List<WiFiObserver> mWifiObservers = new ArrayList<>();
    private List<WifiInfo> mWifiList = new ArrayList<>();
    private List<WifiListInfo> wifiListInfos = new ArrayList<>();

    private static WifiListUtils instance;

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case MSG_SCAN_WIFI:
                    LogUtils.dTag(TAG, "扫描WiFi列表！");
                    if (WifiSupport.isOpenWifi()) {
                        wifiManager.startScan();
                    }
                    mHandler.sendEmptyMessageDelayed(MSG_SCAN_WIFI, DURATION);
                    break;
            }
        }
    };

    private WifiListUtils(Context context) {
        wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        registerReceiver();
    }

    public static WifiListUtils getInstance() {
        if (instance == null) {
            synchronized (WifiListUtils.class) {
                if (instance == null) {
                    instance = new WifiListUtils(Utils.getApp());
                }
            }
        }
        return instance;
    }

    public void registerWifiObserver(WiFiObserver wiFiObserver) {
        if (wiFiObserver != null && !mWifiObservers.contains(wiFiObserver)) {
            mWifiObservers.add(wiFiObserver);
            notifyObserver(wiFiObserver);
        }
    }

    public void removeWifiObserver(WiFiObserver wiFiObserver) {
        if (mWifiObservers.contains(wiFiObserver)) {
            mWifiObservers.remove(wiFiObserver);
        }
    }

    public void updateWifiList() {
        long interval = System.currentTimeMillis() - mLastTimestamp;
        mLastTimestamp = System.currentTimeMillis();
        LogUtils.e(TAG, "更新间隔 : " + interval);
        if (WifiSupport.isOpenWifi()) {
            notifyWifiState(true);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (PermissionUtils.isGranted(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)) {
                    getWifiInfoList();
                    if (mWifiList.isEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                        if (!GpsUtil.isGpsOPen()) {
                            notifyGpsPermissionDeny(false);
                        } else {
                            notifyWifiListChange(mWifiList);
                        }
                    } else {
                        notifyWifiListChange(mWifiList);
                    }
                } else {
                    notifyLocationPermission(false);
                }
            } else {
                getWifiInfoList();
                String wifiSSID = WifiUtil.getWifiSSID();
                boolean connectedWifi = false;
                if (!TextUtils.isEmpty(wifiSSID)) {
                    connectedWifi = true;
                }
                if (mWifiList.isEmpty()) {
                    if (connectedWifi) {
                        notifyLocationPermission(false);
                    } else {
                        if (!LowVersionPermissionUtils.hasLocationPermission()) {
                            notifyLocationPermission(false);
                        } else {
                            notifyWifiListChange(mWifiList);
                        }
                    }
                } else {
                    notifyWifiListChange(mWifiList);
                }
            }
        } else {
            notifyWifiState(false);
        }
        mHandler.removeMessages(MSG_SCAN_WIFI);
        mHandler.sendEmptyMessage(MSG_SCAN_WIFI);
    }

    private void notifyWifiState(boolean open) {
        for (int i = 0; i < mWifiObservers.size(); i++) {
            WiFiObserver wiFiObserver = mWifiObservers.get(i);
            wiFiObserver.onWifiStateChange(open);
        }
    }

    private void notifyGpsState(boolean open) {
        for (int i = 0; i < mWifiObservers.size(); i++) {
            WiFiObserver wiFiObserver = mWifiObservers.get(i);
            wiFiObserver.onGpsStateChange(open);
        }
    }

    private void notifyObserver(WiFiObserver wiFiObserver) {
        if (WifiSupport.isOpenWifi()) {
            wiFiObserver.onWifiStateChange(true);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (PermissionUtils.isGranted(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)) {
                    getWifiInfoList();
                    if (mWifiList.isEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                        if (!GpsUtil.isGpsOPen()) {
                            wiFiObserver.onGpsPermissionDeny();
                        } else {
                            wiFiObserver.onWiFiListInfoChange(wifiListInfos);
                        }
                    } else {
                        wiFiObserver.onWiFiListInfoChange(wifiListInfos);
                    }
                } else {
                    wiFiObserver.onLocationPermissionDeny();
                }
            } else {
                getWifiInfoList();
                wiFiObserver.onWiFiListInfoChange(wifiListInfos);
            }
        } else {
            wiFiObserver.onWifiStateChange(false);
        }
    }

    private void notifyLocationPermission(boolean hasPermission) {
        for (int i = 0; i < mWifiObservers.size(); i++) {
            WiFiObserver wiFiObserver = mWifiObservers.get(i);
            wiFiObserver.onLocationPermissionDeny();
        }
    }

    private void notifyGpsPermissionDeny(boolean hasPermission) {
        for (int i = 0; i < mWifiObservers.size(); i++) {
            WiFiObserver wiFiObserver = mWifiObservers.get(i);
            wiFiObserver.onGpsPermissionDeny();
        }
    }

    private void notifyWifiListChange(List<WifiInfo> wifiInfos) {
        for (int i = 0; i < mWifiObservers.size(); i++) {
            WiFiObserver wiFiObserver = mWifiObservers.get(i);
            wiFiObserver.onWiFiListChange(wifiInfos);
            wiFiObserver.onWiFiListInfoChange(wifiListInfos);
        }
    }

    private void getWifiInfoList() {
        List<ScanResult> scanResults = WifiSupport.sortScaResult();
        List<WifiInfo> wifiInfos = new ArrayList<>();
        for (int i = 0; i < scanResults.size(); i++) {
            ScanResult scanResult = scanResults.get(i);
            WifiInfo wifiInfo = new WifiInfo();
            wifiInfo.setSsid(scanResult.SSID);
            wifiInfo.setState(WifiInfo.STATE_UNCONNECTED);//只要获取都假设设置成未连接，真正的状态都通过广播来确定
            String capabilities = scanResult.capabilities;
            wifiInfo.setCapabilities(capabilities);
            wifiInfo.setLevel(WifiManager.calculateSignalLevel(scanResult.level, WIFI_LEVEL));
            wifiInfo.setSignalStrength(WifiManager.calculateSignalLevel(scanResult.level, 100));
//            wifiInfo.setLevel(WifiSupport.getLevel(scanResult.level));
            if (!TextUtils.isEmpty(capabilities)) {
                if (capabilities.contains("WPA") || capabilities.contains("wpa")) {
                    wifiInfo.setWifiCipherType(WifiSupport.WifiCipherType.WIFICIPHER_WPA);
                } else if (capabilities.contains("WEP") || capabilities.contains("wep")) {
                    wifiInfo.setWifiCipherType(WifiSupport.WifiCipherType.WIFICIPHER_WEP);
                } else {
                    wifiInfo.setWifiCipherType(WifiSupport.WifiCipherType.WIFICIPHER_NOPASS);
                }
            }
            wifiInfo.setFrequency(scanResult.frequency);
            wifiInfo.setScanResult(scanResult);
            wifiInfo.setChannel(WifiSupport.getChannelByFrequency(scanResult.frequency));
            WifiConfiguration wifiConfigBySsid = WifiUtil.getWifiConfigBySsid(wifiInfo.getSsid());
            StringBuilder sb = new StringBuilder();
            if (wifiInfo.getWifiCipherType() == WifiSupport.WifiCipherType.WIFICIPHER_NOPASS) {
                wifiInfo.setAvailableInfo("无需密码的WIFI");
                sb.append("开放WIFI");
            } else if (wifiInfo.getWifiCipherType() == WifiSupport.WifiCipherType.WIFICIPHER_WPA) {
                wifiInfo.setAvailableInfo("需要密码的WIFI");
                sb.append("WPA/WPA2");
            } else if (wifiInfo.getWifiCipherType() == WifiSupport.WifiCipherType.WIFICIPHER_WEP) {
                wifiInfo.setAvailableInfo("需要密码的WIFI");
                sb.append("WEP");
            }
            if (wifiConfigBySsid != null && wifiConfigBySsid.networkId >= 0) {
                wifiInfo.setAvailableInfo("密码已保存");
                wifiInfo.setWifiConfiguration(wifiConfigBySsid);
                wifiInfo.setConfig(true);
            } else {
                wifiInfo.setConfig(false);
            }
            wifiInfo.setAvailable(true);
//            sb.append(" | ");
//            sb.append("CH")
//                    .append(wifiInfo.getChannel());
//            sb.append(" | ")
//                    .append(wifiInfo.getFrequency()).append("Hz");
            wifiInfo.setWifiInfo(sb.toString());
            if (BlackWifiService.getInstance().isBlackWifi(wifiInfo.getSsid())) {
                continue;
            }
            wifiInfos.add(wifiInfo);
            android.net.wifi.WifiInfo connectionInfo = wifiManager.getConnectionInfo();
            if (connectionInfo != null && scanResult.SSID.equals(WifiUtil.formatSSID(connectionInfo.getSSID())) && connectionInfo.getSupplicantState() == SupplicantState.COMPLETED) {
                wifiInfo.setConnected(true);
            } else {
                wifiInfo.setConnected(false);
            }
            wifiInfo.setMac(scanResult.BSSID);
            Collections.sort(wifiInfos);
        }
        mWifiList.clear();
        wifiListInfos.clear();
        for (WifiInfo wifiInfo : wifiInfos) {
            WifiListInfo wifiListInfo = new WifiListInfo();
//            if (wifiInfo.isConnected()) {
//                continue;
//            }
            wifiListInfo.setType(WifiListInfo.TYPE_WIFI_INFO);
            wifiListInfo.setWifiInfo(wifiInfo);
            wifiListInfos.add(wifiListInfo);
        }
        mWifiList.addAll(wifiInfos);
    }

    private void updateList() {
        long dur = System.currentTimeMillis() - mLastUpdateTimestamp;
        if (dur > UPDATE_LIST_TIME) {
            mLastUpdateTimestamp = System.currentTimeMillis();
            updateWifiList();
        }
    }

    private void registerReceiver() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
        if (scanResultReceiver == null) {
            scanResultReceiver = new ScanResultReceiver();
        }
        Utils.getApp().registerReceiver(scanResultReceiver, intentFilter);
        IntentFilter wifiStateFilter = new IntentFilter();
        wifiStateFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        if (wifiStateChangeReceiver == null) {
            wifiStateChangeReceiver = new WifiStateChangeReceiver();
        }
        Utils.getApp().registerReceiver(wifiStateChangeReceiver, wifiStateFilter);
        IntentFilter gpsStateFilter = new IntentFilter();
        gpsStateFilter.addAction(LocationManager.MODE_CHANGED_ACTION);
        if (gpsStateReceiver == null) {
            gpsStateReceiver = new GPSStateReceiver();
        }
        Utils.getApp().registerReceiver(gpsStateReceiver, gpsStateFilter);
    }

    private void unRegisterReceiver() {
        if (scanResultReceiver != null) {
            Utils.getApp().unregisterReceiver(scanResultReceiver);
        }
        if (wifiStateChangeReceiver != null) {
            Utils.getApp().unregisterReceiver(wifiStateChangeReceiver);
        }
        if (gpsStateReceiver != null) {
            Utils.getApp().unregisterReceiver(gpsStateReceiver);
        }
    }

    public void reset() {
        mHandler.removeCallbacksAndMessages(null);
//        unRegisterReceiver();
    }

    public class ScanResultReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
                boolean update = true;
                if (intent.hasExtra(WifiManager.EXTRA_RESULTS_UPDATED)) {
                    update = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
                }
                if (update) {
                    LogUtils.dTag(TAG, "WiFi结果可用广播！");
                    updateList();
//                    updateWifiList();
                }
            }
        }
    }

    public class WifiStateChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
                int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN);
                if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
                    updateWifiList();
                }
                if (wifiState == WifiManager.WIFI_STATE_DISABLED) {
                    updateWifiList();
                }
            }
        }
    }

    public class GPSStateReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
                boolean oPen = GpsUtil.isGpsOPen();
                if (oPen) {
                    updateWifiList();
                } else {
                    updateWifiList();
                }
            }
        }
    }
}

